﻿using System;
using System.Linq;
using Reviewer.Entities;
using Reviewer.Entities.Services;
using System.Collections.Generic;
using System.Threading;
using System.Globalization;

namespace Reviewer.Business.Services
{
    /// <summary>
    /// News Service
    /// </summary>
    internal class NewsService : BaseService, INewsService, INewsAdminService
    {
        internal NewsService() : base() { }

        #region methods (public)
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }

        public News[] GetAll()
        {
            return new Data.NewsRepository().SelectAll().ToArray();
        }

        /// <summary>
        /// Gets the News by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public Reviewer.Entities.News GetById(int id)
        {
            if (id < 1)
            {
                throw new ArgumentOutOfRangeException("id", "Invalid key identifier");
            }

            return new Data.NewsRepository().SelectBy(id);
        }

        /// <summary>
        /// Gets the News by news id.
        /// </summary>
        /// <param name="newsId">The news id.</param>
        /// <returns></returns>
        public Reviewer.Entities.News[] GetByNewsId(Guid newsId)
        {
            if (newsId.Equals(Guid.Empty))
            {
                throw new ArgumentOutOfRangeException("newsId", "Invalid key identifier");
            }

            return new Data.NewsRepository().SelectByAlternateKey(newsId).ToArray();
        }

        /// <summary>
        /// Gets the latest News.
        /// </summary>
        /// <param name="topCount">The top count.</param>
        /// <returns><c ref="News"/></returns>
        public Reviewer.Entities.News[] GetLatest(int topCount)
        {
            if (topCount <= 0 || topCount > 50)
            {
                throw new ArgumentOutOfRangeException("topCount", "Invalid top count");
            }

            return new Data.NewsRepository().GetLatest(topCount).ToArray();
        }

        public NewsFormat[] GetAssociatedGameFormats(Guid newsId)
        {
            return new Data.NewsFormatRepository().SelectByAlternateKey(newsId).ToArray();
        }

        public NewsGameRelation[] GetGameRelations(Guid newsId)
        {
            return new Data.NewsGameRelationRepository().SelectByAlternateKey(newsId).ToArray();
        }

        public News[] GetAllByGameRelation(Guid gameId)
        {
            return new Data.NewsRepository().SelectByGameRelation(gameId).ToArray();
        }

        public News[] Search(string searchString)
        {
            return new Data.NewsRepository().Search(searchString).ToArray();
        }

        public News[] GetAllByFormat(int formatId)
        {
            return new Data.NewsRepository().SelectByFormat(formatId).ToArray();
        }

        public ICollection<News> Search(Int32? newsType, Int32? format, int maxResults)
        {
            return new Data.NewsRepository().Search(newsType, format, maxResults);
        }

        #endregion

        #region INewsAdminService Members

        public Reviewer.Entities.News Save(Reviewer.Entities.News newsItem)
        {
            if (newsItem.Id < 1)
            {
                if (newsItem.NewsId == null || newsItem.NewsId.Equals(Guid.Empty))
                {
                    newsItem.NewsId = Guid.NewGuid();
                    Writer writer = ServiceFactory.WriterService.Find().FirstOrDefault(t => t.LogOnName.ToUpperInvariant().Equals(Thread.CurrentPrincipal.Identity.Name.ToUpperInvariant(), StringComparison.Ordinal));
                    if (writer == null)
                    {
                        throw new System.UnauthorizedAccessException("Invalid writer credentials");
                    }

                    newsItem.NewsDate = DateTime.Now;
                    newsItem.Author = writer.Id;
                }

                News newItem = new Data.NewsRepository().Create(newsItem);

                #region Add FrontPage Post
                FrontPagePost post = new FrontPagePost();
                post.Title = newItem.Title;
                post.PostType = "NEWS";
                if (newItem.Header.Length > 150)
                {
                    post.Text = newItem.Header.Substring(0, 150) + "...";
                }
                else
                {
                    post.Text = newItem.Header;
                }
                post.Link = newItem.Id.ToString(CultureInfo.InvariantCulture);
                post.Date = DateTime.Now.Date;
                ServiceFactory.FrontPagePostAdminService.Save(post);
                #endregion

                return newItem;
            }

            return new Data.NewsRepository().Update(newsItem);
        }

        public bool Delete(Reviewer.Entities.News newsItem)
        {
            return this.DeleteById(newsItem.Id);
        }

        public bool DeleteById(int id)
        {
            News item = this.GetById(id);
            return this.DeleteByNewsId(item.NewsId);
        }

        public bool DeleteByNewsId(Guid newsId)
        {
            new Data.NewsGameRelationRepository().DeleteByAlternateKey(newsId);
            new Data.NewsFormatRepository().DeleteByAlternateKey(newsId);
            new Data.NewsRepository().DeleteByAlternateKey(newsId);
            return true;
        }

        public void SetAssociatedGameFormats(Guid newsId, NewsFormat[] formats)
        {
            Data.NewsFormatRepository repository = new Reviewer.Data.NewsFormatRepository();

            List<NewsFormat> existingFormats = repository.SelectByAlternateKey(newsId).ToList();
            List<NewsFormat> newFormats = formats.ToList();

            //remove deleted
            for (int i = 0; i < existingFormats.Count; i++)
            {
                if (newFormats.FirstOrDefault(t => t.FormatId.Equals(existingFormats[i].FormatId)) == null)
                {
                    repository.Delete(existingFormats[i].Id);

                    newFormats.RemoveAll(t => t.FormatId.Equals(existingFormats[i].FormatId));
                    existingFormats.RemoveAt(i);
                    i--;
                }
            }

            //add new
            foreach (NewsFormat format in newFormats)
            {
                repository.Create(format);
            }
        }

        public void SetGameRelations(Guid newsId, NewsGameRelation[] gameRelations)
        {
            Data.NewsGameRelationRepository repository = new Reviewer.Data.NewsGameRelationRepository();

            List<NewsGameRelation> existingRelations = repository.SelectByAlternateKey(newsId).ToList();
            List<NewsGameRelation> newRelations = gameRelations.ToList();

            for (int i = 0; i < existingRelations.Count; i++)
            {
                if (newRelations.FirstOrDefault(t => t.GameId.Equals(existingRelations[i].GameId)) == null)
                {
                    repository.Delete(existingRelations[i].Id);

                    newRelations.RemoveAll(t => t.GameId.Equals(existingRelations[i].GameId));
                    existingRelations.RemoveAt(i);
                    i--;
                }
            }

            foreach (NewsGameRelation relation in newRelations)
            {
                repository.Create(relation);
            }
        }

        #endregion
    }
}
